% \iffalse meta-comment
%
% Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle
% Copyright (C) 2004-2010 Frank Mittelbach, The LaTeX Project
% Copyright (C) 2011-2025
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
% This file is part of the LaTeX base system.
% -------------------------------------------
%
% It may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%    https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This file has the LPPL maintenance status "maintained".
%
% The list of all files belonging to the LaTeX base distribution is
% given in the file `manifest.txt'. See also `legal.txt' for additional
% information.
%
% The list of derived (unpacked) files belonging to the distribution
% and covered by LPPL is defined by the unpacking scripts (with
% extension .ins) which are part of the distribution.
%
% \fi
%
% \iffalse
%
%%% From File: lttemplates.dtx
%
%<*driver>
% \fi
\ProvidesFile{lttemplates.dtx}
  [2025-11-21 v1.0g LaTeX Kernel (Prototype document functions)]
% \iffalse
\documentclass{l3doc}
\GetFileInfo{lttemplates.dtx}
\begin{document}
  \DocInput{lttemplates.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \texttt{lttemplates.dtx} code\thanks{This file has version
%    \fileversion\ dated \filedate, \copyright\ \LaTeX\
%    Project.}}
% \author{^^A
%  Frank Mittelbach, Chris Rowley, David Carlisle, \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \maketitle
%
% \section{Introduction}
%
% There are three broad \enquote{layers} between putting down ideas into
% a source file and ending up with a typeset document. These layers of
% document writing are
% \begin{enumerate}
%   \item authoring of the text with mark-up;
%   \item document layout design;
%   \item implementation (with \TeX{} programming) of the design.
% \end{enumerate}
% We write the text as an author, and we see the visual output of the design
% after the document is generated; the \TeX{} implementation in the middle is
% the glue between the two.
%
% \LaTeX{}'s greatest success has been to standardise a system of mark-up that
% balances the trade-off between ease of reading and ease of writing to suit
% almost all forms of technical writing. It's
% other original strength was a good background in typographical design; while
% the standard \LaTeXe{} classes look somewhat dated now in terms of their
% visual design, their typography is generally sound (barring the occasional
% minor faults).
%
% However, \LaTeXe{} has always lacked a standard approach to customising
% the visual design of a document. Changing the looks of the standard classes
% involved either:
% \begin{itemize}
%   \item Creating a new version of the implementation code of the class and
%     editing it.
%   \item Loading one of the many packages to customise certain elements of
%     the standard classes.
%   \item Loading a completely different document class, such as
%     \textsf{KOMA-Script} or \textsf{memoir}, that allows easy customization.
% \end{itemize}
% All three of these approaches have their drawbacks and learning curves.
%
% The idea behind \pkg{lttemplates} is to cleanly separate the three layers
% introduced at the beginning of this section, so that document authors who
% are not programmers can easily change the design of their documents.
% \pkg{lttemplates} also makes it easier for \LaTeX{} programmers to provide
% their own customizations on top of a pre-existing class.
%
% \section{What is a document?}
%
% Besides the textual content of the words themselves, the source file
% of a document contains mark-up elements that add structure to the
% document. These elements include sectional divisions, figure/table
% captions, lists of various sorts, theorems/proofs, and so on.
% The list will be different for every document that can be written.
%
% Each element can be represented logically without worrying about the
% formatting, with mark-up such as \cs{section}, \cs{caption},
% |\begin{enumerate}| and so on. The output of each one of these
% document elements will be a typeset representation of the information
% marked up, and the visual arrangement and design of these elements
% can vary widely in producing a variety of desired outcomes.
%
% For each type of document element, there may be design variations that
% contain the same sort of information but present it in slightly
% different ways. For example, the difference between a numbered and an
% unnumbered section, \cs{section} and |\section*|, or the difference
% between an itemized list or an enumerated list.
%
% There are three distinct layers in the definition of
% \enquote{a document} at this level
% \begin{enumerate}
%   \item semantic elements such as the ideas of sections and lists;
%   \item a set of design solutions for representing these elements
%     visually;
%   \item specific variations for these designs that represent the
%     elements in the document.
% \end{enumerate}
% In the parlance of the template system, these are called types,
% templates, and instances, and they are discussed below in sections
% \ref{sec:types}, \ref{sec:templates}, and~\ref{sec:instances},
% respectively.
%
% \section {Types, templates, and instances}
%
% By formally declaring documents to be composed of mark-up elements
% grouped into types, which are interpreted and typeset with a set of
% templates, each of which has one or more instances with which to
% compose each and every semantic unit of the text, we can cleanly
% separate the components of document construction.
%
% All of the structures provided by the template system are global,
% and do not respect \TeX{} grouping.
%
% \section{Template types}
% \label{sec:types}
%
% An \emph{template type} (sometimes just \enquote{type}) is an
% abstract idea of a document element that takes a fixed number of
% arguments corresponding to the information from the document author
% that it is representing. A sectioning type, for example, might take
% three inputs: \enquote{title}, \enquote{short title}, and
% \enquote{label}.
%
% Any given document class will define which types are to be
% used in the document, and any template of a given type can be
% used to generate an instance for the type. (Of course, different
% templates will produce different typeset representations, but the
% underlying content will be the same.)
%
% \begin{function}{\NewTemplateType}
%   \begin{syntax}
%     \cs{NewTemplateType} \Arg{template type} \Arg{no. of args}
%   \end{syntax}
%  This function defines an \meta{template type} taking
%  \meta{number of arguments}, where the \meta{type} is an
%  abstraction as discussed above. For example,
%   \begin{verbatim}
%     \NewTemplateType{sectioning}{3}
%   \end{verbatim}
%  creates a type \enquote{sectioning}, where each use of that
%  type will need three arguments.
% \end{function}
%
% \section{Templates}
% \label{sec:templates}
%
% A \emph{template} is a generalized design solution for representing
% the information of a specified type. Templates that do the same
% thing, but in different ways, are grouped together by their type
% and given separate names. There are two important parts to a template:
% \begin{itemize}
%   \item the parameters it takes to vary the design it is producing;
%   \item the implementation of the design.
% \end{itemize}
% As a document author or designer does not care about the
% implementation but rather only the interface to the template, these two
% aspects of the template definition are split into two independent
% declarations, \cs{DeclareTemplateInterface} and
% \cs{DeclareTemplateCode}.
%
% \begin{function}{\DeclareTemplateInterface}
%   \begin{syntax}
%     \cs{DeclareTemplateInterface}
%     ~~\Arg{type} \Arg{template} \Arg{no.~of args}
%     ~~\Arg{key list}
%   \end{syntax}
%   A \meta{template} interface is declared for a particular
%   \meta{type}, where the \meta{number of arguments} must
%   agree with the type declaration. The interface itself is
%   defined by the \meta{key list}, which is itself a key--value list
%   taking a specialized format:
%   \begin{quotation}
%     \obeylines
%     \noindent
%      \meta{key1}~":"~\meta{key type1}~","
%      \meta{key2}~":"~\meta{key type2}~","
%      \meta{key3}~":"~\meta{key type3}~"="~\meta{default3}~","
%      \meta{key4}~":"~\meta{key type4}~"="~\meta{default4}~","
%      \ldots
%    \end{quotation}
%   Each \meta{key} name should consist of \textsc{ascii} characters,
%   with the exception of |,|, |=| and |:|. The recommended form
%   for key names is to use lower case letters, with dashes to separate
%   out different parts. Spaces are ignored in key names, so they can be
%   included or missed out at will. Each \meta{key} must have a
%   \meta{key type}, which defines the type of input that the \meta{key}
%   requires. A full list of key types is given in
%   Table~\ref{tab:key-types}.  Each key may have a \meta{default}
%   value, which will be used in by the template if the \meta{key} is
%   not set explicitly. The \meta{default} should be of the correct
%   form to be accepted by the \meta{key type} of the \meta{key}: this
%   is not checked by the code. Expressions for numerical values are
%   evaluated when the template is used, thus for example values given
%   in terms of |em| or |ex| will be set respecting the prevailing font.
% \end{function}
%
%   \begin{table}
%     \centering
%     \begin{tabular}{>{\ttfamily}ll}
%       \toprule
%       \multicolumn{1}{l}{Key-type} & Description of input \\
%       \midrule
%       boolean    & \texttt{true} or \texttt{false}            \\
%       choice\Arg{choices}
%         & A list of pre-defined \meta{choices} \\
%       commalist  & A comma-separated list                        \\
%       function\Arg{$N$}
%         & A function definition with $N$ arguments
%          ($N$ from $0$ to $9$) \\
%       instance\Arg{name}
%         & An instance of type \meta{name} \\
%       integer    & An integer or integer expression            \\
%       length     & A fixed length                              \\
%       muskip     & A math length with shrink and stretch components \\
%       real       & A real (floating point) value               \\
%       skip       & A length with shrink and stretch components \\
%       tokenlist  & A token list: any text or commands          \\
%       \bottomrule
%     \end{tabular}
%     \caption{Key-types for defining template interfaces with
%       \cs{DeclareTemplateInterface}.}
%     \label{tab:key-types}
%   \end{table}
%
% \begin{function}{\KeyValue}
%   \begin{syntax}
%     \cs{KeyValue} \Arg{key name}
%   \end{syntax}
%   There are occasions where the default (or value) for one key
%   should be taken from another. The \cs{KeyValue} function can be
%   used to transfer this information without needing to know the
%   internal implementation of the key:
%   \begin{verbatim}
%     \DeclareTemplateInterface { type } { template } { no. of args }
%       {
%         key-name-1 : key-type = value ,
%         key-name-2 : key-type = \KeyValue { key-name-1 },
%         ...
%       }
%   \end{verbatim}
% \end{function}
%
% \begin{function}{\DeclareTemplateCode}
%   \begin{syntax}
%     \cs{DeclareTemplateCode}
%     ~~\Arg{type} \Arg{template} \Arg{no.~of args}
%     ~~\Arg{key bindings} \Arg{code}
%   \end{syntax}
%   The relationship between a templates keys and the internal
%   implementation is created using the \cs{DeclareTemplateCode}
%   function. As with \cs{DeclareTemplateInterface}, the
%   \meta{template} name is given along with the \meta{type}
%   and \meta{number of arguments} required. The \meta{key bindings}
%   argument is a key--value list which specifies the relationship
%   between each \meta{key} of the template interface with an
%   underlying \meta{variable}.
%
%   \begin{quotation}
%     \obeylines
%     \noindent
%     \meta{key1}~"="~\meta{variable1},
%     \meta{key2}~"="~\meta{variable2},
%     \meta{key3}~"="~global~\meta{variable3},
%     \meta{key4}~"="~global~\meta{variable4},
%     \ldots
%   \end{quotation}
%   With the exception of the choice, code and function key types,
%   the \meta{variable} here should be the name of an existing
%   \LaTeX3 register. As illustrated, the key word \enquote{global}
%   may be included in the listing to indicate that the \meta{variable}
%   should be assigned globally. A full list of variable bindings is
%   given in Table~\ref{tab:key-vars}.
%
%   The \meta{code} argument of \cs{DeclareTemplateCode} is used
%   as the replacement text for the template when it is used, either
%   directly or as an instance. This may therefore accept arguments
%   |#1|, |#2|, \emph{etc}.~as detailed by the \meta{number of arguments}
%   taken by the type.
% \end{function}
%
%   \begin{table}
%     \centering
%     \begin{tabular}{>{\ttfamily}ll}
%       \toprule
%       \multicolumn{1}{l}{Key-type} & Description of binding \\
%       \midrule
%       boolean    & Boolean variable, \emph{e.g}.~\cs{l_tmpa_bool}      \\
%       choice
%         & List of choice implementations
%         (see Section~\ref{sec:choices-key}) \\
%       commalist  & Comma list, \emph{e.g}.~\cs{l_tmpa_clist}           \\
%       function
%         & Function taking $N$ arguments, \emph{e.g}.~\cs{use_i:nn}     \\
%       instance \\
%       integer    & Integer variable, \emph{e.g}.~\cs{l_tmpa_int}       \\
%       length     & Dimension variable, \emph{e.g}.~\cs{l_tmpa_dim}     \\
%       muskip     & Muskip variable, \emph{e.g}.~\cs{l_tmpa_muskip}     \\
%       real       & Floating-point variable, \emph{e.g}.~\cs{l_tmpa_fp} \\
%       skip       & Skip variable, \emph{e.g}.~\cs{l_tmpa_skip}         \\
%       tokenlist  & Token list variable, \emph{e.g}.~\cs{l_tmpa_tl}     \\
%       \bottomrule
%     \end{tabular}
%     \caption{Bindings required for different key types when defining
%       template implementations with \cs{DeclareTemplateCode}. Apart
%       from \texttt{choice} and \texttt{function}
%       all of these accept the key word \texttt{global} to carry
%       out a global assignment.}
%     \label{tab:key-vars}
%   \end{table}
%
% \begin{function}{\AssignTemplateKeys}
%   \begin{syntax}
%     \cs{AssignTemplateKeys}
%   \end{syntax}
%   In the final argument of \cs{DeclareTemplateCode} the assignment of
%   keys defined by the template may be delayed by including the command
%   \cs{AssignTemplateKeys}. If this is \emph{not} present, keys are assigned
%   immediately before the template code. If an
%    \cs{AssignTemplateKeys} command is
%   present, assignment is delayed until this point. Note that the
%   command must be \emph{directly} present in the code, not placed
%   within a nested command/macro.
% \end{function}
%
% \begin{function}{\SetKnownTemplateKeys,\SetTemplateKeys,\UnusedTemplateKeys}
%   \begin{syntax}
%   \cs{SetKnownTemplateKeys} \Arg{type} \Arg{template} \Arg{keyvals}
%   \cs{SetTemplateKeys}      \Arg{type} \Arg{template} \Arg{keyvals}
%
%   \cs{UnusedTemplateKeys} \% all \meta{keyvals} unused by previous \cs{SetKnownTemplateKeys}
%   \end{syntax}
%
%    In the final argument of \cs{DeclareTemplateCode} one can also
%    overwrite (some of) the current template key value settings by
%    using the command \cs{SetKnownTemplateKeys} or
%    \cs{SetTemplateKeys}, i.e., they can overwrite the template default values and
%    the values assigned by the instance.
%
%    The \cs{SetKnownTemplateKeys} and \cs{SetTemplateKeys} commands
%    are only supported within the code of a template; using them
%    elsewhere has unpredictable results.  If they are used together
%    with \cs{AssignTemplateKeys} then the latter command should come first
%    in the template code.
%
%    The main use case for these commands is the situation where there
%    is an argument (normally \texttt{\#1}) to the template in which
%    a key/value list can be specified that overwrites the normal
%    settings. In that case one could use
%\begin{quote}
%  \verb/\SetKnownTemplateKeys/\Arg{type}\Arg{template}\verb/{#1}/
%\end{quote}
%    to process this key/value list inside the template.
%
%    If \cs{SetKnownTemplateKeys} is executed and the \meta{keyvals} argument contains keys not known to the
%    \meta{template} they are simply ignored and stored in the
%    tokenlist \cs{UnusedTemplateKeys}
%    without generating an error. This way it is possible to
%    apply the same key/val list specified by the user on a
%    document-level command or environment to several templates, which
%    is useful, if the command or environment is implemented by calling several different template instances.
%
% \end{function}
%
%    As a variation of that, you can use this key/val
%    list the first time, and for the next template instance use what remains in
%    \cs{UnusedTemplateKeys} (i.e., the key/val list with only the keys that have not been processed previously). The final processing step could then be
%    \cs{SetTemplateKeys}, which unconditionally attempts to set the
%    \meta{keyvals} received in its third argument. This command
%    complains if any of them are unknown keys. Alternatively, you
%    could use \cs{SetKnownTemplateKeys} and afterwards check whether \cs{UnusedTemplateKeys} is empty.\footnote{Using
%    \cs{SetTemplateKeys} exposes the inner structure of the template
%    keys when generating an error. This is something one may want to
%    avoid as it can be confusing to the user, especially if several
%    templates are involved. In that
%    case use  \cs{SetKnownTemplateKeys} and afterwards check whether
%    \cs{UnusedTemplateKeys} is empty;  if it is not empty then generate your own
%    error message.}
%
%    For example, a list, such as \env{enumerate}, is made up from a
%    \texttt{blockenv}, \texttt{block}, \texttt{list}, and a
%    \texttt{para} template and in the single user-supplied optional
%    argument of \env{enumerate} key/values for any of these templates might
%    be specified.
%
%    In fact, in the particular example of list environments,
%    the supplied key/value list is also saved and then applied to each
%    \cs{item} which is implemented through an \texttt{item}
%    template. This way, one can specify one-off settings for all the items
%    of a single list (on the environment level), as well as to
%    individual items within that list (by specifying them in the
%    optional argument of an \cs{item}).  With
%    \cs{SetKnownTemplateKeys} and \cs{SetTemplateKeys} working
%    together, it is possible to provide this flexibility and still
%    alert the user when one of their keys is misspelled.
%
%    On the other hand you may want to allow for
%    \enquote{misspellings} without generating an error or a
%    warning. For example, if you define a template that accepts only a
%    few keys, you might just want to ignore anything specified in the
%    source when you use this template in place of a different one,
%    without the need to alter the document source. Or you might just
%    generate a warning message, which is easy, given that the unused
%    key/values are available in the \cs{UnusedTemplateKeys} variable.
%
%
% \begin{function}{\DeclareTemplateCopy}
%   \begin{syntax}
%     \cs{DeclareTemplateCopy}
%     ~~\Arg{type} \Arg{template2} \Arg{template1}
%   \end{syntax}
%   Copies \meta{template1} of \meta{type} to a new name \meta{template2}:
%   the copy can then be edited independent of the original.
% \end{function}
%
% \section{Multiple choices}
% \label{sec:choices-key}
%
% The \texttt{choice} key type implements multiple choice input. At the
% interface level, only the list of valid choices is needed:
% \begin{verbatim}
%   \DeclareTemplateInterface { foo } { bar } { 0 }
%     { key-name : choice { A, B, C } }
% \end{verbatim}
% where the choices are given as a comma-list (which must therefore
% be wrapped in braces). A default value can also be given:
% \begin{verbatim}
%   \DeclareTemplateInterface { foo } { bar } { 0 }
%     { key-name : choice { A, B, C } = A }
% \end{verbatim}
%
% At the implementation level, each choice is associated with code,
% using a nested key--value list.
% \begin{verbatim}
%   \DeclareTemplateCode { foo } { bar } { 0 }
%     {
%       key-name =
%         {
%           A = Code-A ,
%           B = Code-B ,
%           C = Code-C
%         }
%      }
%      { ... }
% \end{verbatim}
% The two choice lists should match, but in the implementation a
% special \texttt{unknown} choice is also available. This can be used
% to ignore values and implement an \enquote{else} branch:
% \begin{verbatim}
%   \DeclareTemplateCode { foo } { bar } { 0 }
%     {
%       key-name =
%         {
%           A       = Code-A ,
%           B       = Code-B ,
%           C       = Code-C ,
%           unknown = Else-code
%         }
%      }
%      { ... }
% \end{verbatim}
% The \texttt{unknown} entry must be the last one given, and should
% \emph{not} be listed in the interface part of the template.
%
% For keys which accept the values \texttt{true} and \texttt{false}
% both the boolean and choice key types can be used. As template
% interfaces are intended to prompt clarity at the design level, the
% boolean key type should be favored, with the choice type reserved
% for keys which take arbitrary values.
%
% \section{Instances}
% \label{sec:instances}
%
% After a template is defined it still needs to be put to use. The
% parameters that it expects need to be defined before it can be used in
% a document. Every time a template has parameters given to it, an
% \emph{instance} is created, and this is the code that ends up in the
% document to perform the typesetting of whatever pieces of information
% are input into it.
%
% For example, a template might say \enquote{here is a section with or
% without a number that might be centered or left aligned and print its
% contents in a certain font of a certain size, with a bit of a gap
% before and after it} whereas an instance declares \enquote{this is a
% section with a number, which is centered and set in $12\,\text{pt}$
% italic with a $10\,\text{pt}$ skip before and a
% $12\,\text{pt}$ skip after it}. Therefore, an instance is just a
% frozen version of a template with specific settings as chosen by the
% designer.
%
% \begin{function}{\DeclareInstance}
%   \begin{syntax}
%     \cs{DeclareInstance}
%     ~~\Arg{type} \Arg{instance} \Arg{template} \Arg{parameters}
%   \end{syntax}
%   This function uses a \meta{template} for an \meta{type}
%   to create an \meta{instance}. The \meta{instance} will be set
%   up using the \meta{parameters}, which will set some of the
%   \meta{keys} in the \meta{template}.
%
%   As a practical example, consider a type for document sections
%   (which might include chapters, parts, sections, \emph{etc}.), which
%   is called \texttt{sectioning}. One possible template for this
%   type might be called \texttt{basic}, and one instance of this
%   template would be a numbered section. The instance declaration might
%   read:
%   \begin{verbatim}
%     \DeclareInstance { sectioning } { section-num } { basic }
%       {
%         numbered      = true ,
%         justification = center ,
%         font          =\normalsize\itshape ,
%         before-skip   = 10pt ,
%         after-skip    = 12pt ,
%       }
%   \end{verbatim}
%   Of course, the key names here are entirely imaginary, but illustrate
%   the general idea of fixing some settings.
% \end{function}
%
% \begin{function}[EXP]{\InstanceValue}
%   \begin{syntax}
%     \cs{InstanceValue} \Arg{type} \Arg{instance} \Arg{key}
%   \end{syntax}
%   Expands to the current value for the \meta{key} stored in the
%   \meta{instance} of \meta{type}. If the \meta{instance} does not exist,
%   the expansion is empty. The result is returned within the
%   |\unexpanded| primitive (|\exp_not:n|),
% \end{function}
%
% \begin{function}{\IfInstanceExistsT, \IfInstanceExistsF, \IfInstanceExistsTF}
%   \begin{syntax}
%     \cs{IfInstanceExistsTF} \Arg{type} \Arg{instance} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the named \meta{instance} of a \meta{type} exists, and
%   then inserts the appropriate code into the input stream.
% \end{function}
%
% \begin{function}{\DeclareInstanceCopy}
%   \begin{syntax}
%     \cs{DeclareInstanceCopy}
%     ~~\Arg{type} \Arg{instance2} \Arg{instance1}
%   \end{syntax}
%   Copies the \meta{values} for \meta{instance1} for an
%   \meta{type} to \meta{instance2}.
% \end{function}
%
% \section{Document interface}
%
% After the instances have been chosen, document commands must be
% declared to use those instances in the document. \cs{UseInstance}
% calls instances directly, and this command should be used internally
% in document-level mark-up.
%
% \begin{function}{\UseInstance}
%   \begin{syntax}
%     \cs{UseInstance}
%     ~~\Arg{type} \Arg{instance} \meta{arguments}
%   \end{syntax}
%   Uses an \meta{instance} of the \meta{type}, which will require
%   \meta{arguments} as determined by the number specified for the
%   \meta{type}. The \meta{instance} must have been declared
%   before it can be used, otherwise an error is raised.
% \end{function}
%
% \begin{function}{\UseTemplate}
%   \begin{syntax}
%     \cs{UseTemplate} \Arg{type} \Arg{template}
%     ~~\Arg{settings} \meta{arguments}
%   \end{syntax}
%   Uses the \meta{template} of the specified \meta{type},
%   applying the \meta{settings} and absorbing \meta{arguments} as
%   detailed by the \meta{type} declaration. This in effect
%   is the same as creating an instance using \cs{DeclareInstance}
%   and immediately using it with \cs{UseInstance}, but without the
%   instance having any further existence. This command is therefore useful when
%   a template needs to be used only once.
%
%   This function can also be used as the argument to \texttt{instance}
%   key types:
%   \begin{verbatim}
%     \DeclareInstance { type } { template } { instance }
%       {
%         instance-key =
%           \UseTemplate { type2 } { template2 } { <settings> }
%       }
%   \end{verbatim}
% \end{function}
%
% \section{Changing existing definitions}
%
% Template parameters may be assigned specific defaults for instances
% to use if the instance declaration doesn't explicit set those
% parameters. In some cases, the document designer will wish to edit
% these defaults to allow them to \enquote{cascade} to the instances.
% The alternative would be to set each parameter identically for each
% instance declaration, a tedious and error-prone process.
%
% \begin{function}{\EditTemplateDefaults}
%   \begin{syntax}
%     \cs{EditTemplateDefaults}
%     ~~\Arg{type} \Arg{template} \Arg{new defaults}
%   \end{syntax}
%   Edits the \meta{defaults} for a \meta{template} for an
%   \meta{type}. The \meta{new defaults}, given as a key--value
%   list, replace the existing defaults for the \meta{template}. This
%   means that the change will apply to instances declared after the
%   editing, but that instances which have already been created are
%   unaffected.
% \end{function}
%
% \begin{function}{\EditInstance}
%   \begin{syntax}
%     \cs{EditInstance}
%     ~~\Arg{type} \Arg{instance} \Arg{new values}
%   \end{syntax}
%   Edits the \meta{values} for an \meta{instance} for an
%   \meta{type}. The \meta{new values}, given as a key--value
%   list, replace the existing values for the \meta{instance}. This
%   function is complementary to \cs{EditTemplateDefaults}:
%   \cs{EditInstance} changes a single instance while leaving the
%   template untouched.
% \end{function}
%
% \subsection{Expanding the values of keys}
%
% To allow the user to apply expansion of values when the key is set,
% key names can be
% followed by an expansion specifier. This is given by appending |:| and a
% single letter specifier to the key name. These letters are the normal
% argument specifiers for \pkg{expl3}, thus they may be one of \texttt{n}
% (redundant but supported), \texttt{o}, \texttt{V}, \texttt{v}, \texttt{e},
% \texttt{N} (again redundant) or \texttt{c}. Expansion of a control
% sequence name is particularly
% useful when you need to refer to an internal \LaTeXe{} or an L3 programming
% layer variable, e.g.,
% \begin{verbatim}
%   key-a:c =  @itemdepth , % use \@itemdepth as the value
%   key-b:v =  @itemdepth   % use the current value of \@itempdepth as the value
% \end{verbatim}
%
% \section{Getting information about templates and instances}
%
% \begin{function}{\ShowInstanceValues}
%   \begin{syntax}
%    \cs{ShowInstanceValues} \Arg{type} \Arg{instance}
%   \end{syntax}
%   Shows the \meta{values} for an \meta{instance} of the given
%   \meta{type} at the terminal.
% \end{function}
%
% \begin{function}{\ShowTemplateCode}
%   \begin{syntax}
%     \cs{ShowTemplateCode} \Arg{type} \Arg{template}
%   \end{syntax}
%   Shows the \meta{code} of a \meta{template} for an \meta{type}
%   in the terminal.
% \end{function}
%
% \begin{function}{\ShowTemplateDefaults}
%   \begin{syntax}
%     \cs{ShowTemplateDefaults} \Arg{type} \Arg{template}
%   \end{syntax}
%   Shows the \meta{default} values of a \meta{template} for an
%   \meta{type} in the terminal.
% \end{function}
%
% \begin{function}{\ShowTemplateInterface}
%   \begin{syntax}
%     \cs{ShowTemplateInterface} \Arg{type} \Arg{template}
%   \end{syntax}
%  Shows the \meta{keys} and associated \meta{key types} of a
%   \meta{template} for an \meta{type} in the terminal.
% \end{function}
%
% \begin{function}{\ShowTemplateVariables}
%   \begin{syntax}
%     \cs{ShowTemplateVariables} \Arg{type} \Arg{template}
%   \end{syntax}
%   Shows the \meta{variables} and associated \meta{keys} of a
%   \meta{template} for an \meta{type} in the terminal. Note that
%   \texttt{code} and \texttt{choice} keys do not map directly to variables
%   but to arbitrary code. For \texttt{choice} keys, each valid choice
%   is shown as a separate entry in the list, with the key name and choice
%   separated by a space, for example
%   \begin{verbatim}
%     Template 'example' of type 'example' has variable mapping:
%     >  demo unknown  =>  \def \demo {?}
%     >  demo c  =>  \def \demo {c}
%     >  demo b  =>  \def \demo {b}
%     >  demo a  =>  \def \demo {a}.
%   \end{verbatim}
%   would be shown for a choice key \texttt{demo} with valid choices
%   \texttt{a}, \texttt{b} and \texttt{c}, plus code for an \texttt{unknown}
%   branch.
% \end{function}
%
% \MaybeStop{\setlength\IndexMin{200pt}\PrintIndex}
%
% \section{The implementation}
%
%    \begin{macrocode}
%<@@=template>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*2ekernel>
\message{templates,}
%</2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*2ekernel|latexrelease>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\NewModuleRelease{2024/06/01}{lttemplates}
%<latexrelease>                 {Prototype~document~commands}%
%    \end{macrocode}
%
% \subsection{Variables and constants}
%
% \begin{variable}
%   {
%     \c_@@_code_root_tl      ,
%     \c_@@_defaults_root_tl  ,
%     \c_@@_instances_root_tl ,
%     \c_@@_keytypes_root_tl  ,
%     \c_@@_key_order_root_tl ,
%     \c_@@_restrict_root_tl  ,
%     \c_@@_values_root_tl    ,
%     \c_@@_vars_root_tl
%   }
%   So that literal values are kept to a minimum.
%    \begin{macrocode}
\tl_const:Nn \c_@@_code_root_tl      { template~code~>~ }
\tl_const:Nn \c_@@_defaults_root_tl  { template~defaults~>~ }
\tl_const:Nn \c_@@_instances_root_tl { template~instance~>~  }
\tl_const:Nn \c_@@_keytypes_root_tl  { template~key~types~>~ }
\tl_const:Nn \c_@@_key_order_root_tl { template~key~order~>~ }
\tl_const:Nn \c_@@_values_root_tl    { template~values~>~ }
\tl_const:Nn \c_@@_vars_root_tl      { template~vars~>~ }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_@@_keytypes_arg_seq}
%   A list of keytypes which also need additional data (an argument),
%   used to parse the keytype correctly.
%    \begin{macrocode}
\seq_const_from_clist:Nn \c_@@_keytypes_arg_seq
  { choice , function , instance }
%    \end{macrocode}
%  \end{variable}
%
% \begin{variable}{\g_@@_type_prop}
%   For storing types and the associated number of arguments.
%    \begin{macrocode}
\prop_new:N \g_@@_type_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_assignments_tl}
%   When creating an instance, the assigned values are collected here.
%    \begin{macrocode}
\tl_new:N \l_@@_assignments_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_default_tl}
%   The default value for a key is recovered here from the property list
%   in which it is stored.
%    \begin{macrocode}
\tl_new:N \l_@@_default_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_error_bool}
%   A flag for errors to be carried forward.
%    \begin{macrocode}
\bool_new:N \l_@@_error_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_global_bool}
%   Used to indicate that assignments should be global.
%    \begin{macrocode}
\bool_new:N \l_@@_global_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_key_name_tl    ,
%     \l_@@_keytype_tl     ,
%     \l_@@_keytype_arg_tl ,
%     \l_@@_value_tl       ,
%     \l_@@_var_tl
%   }
%   When defining each key in a template, the name and type of the key
%   need to be separated and stored. Any argument needed by the
%   keytype is also stored separately.
%    \begin{macrocode}
\tl_new:N \l_@@_key_name_tl
\tl_new:N \l_@@_keytype_tl
\tl_new:N \l_@@_keytype_arg_tl
\tl_new:N \l_@@_value_tl
\tl_new:N \l_@@_var_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_value_exp_str}
% \changes{2025-07-08}{v1.0f}{New variable}
%    \begin{macrocode}
\str_new:N \l_@@_value_exp_str
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_keytypes_prop ,
%     \l_@@_key_order_seq ,
%     \l_@@_values_prop   ,
%     \l_@@_vars_prop
%   }  
%   To avoid needing too many difficult-to-follow csname assignments,
%   various scratch token registers are used to build up data, which is
%   then transferred
%    \begin{macrocode}
\prop_new:N \l_@@_keytypes_prop
\seq_new:N \l_@@_key_order_seq
\prop_new:N \l_@@_values_prop
\prop_new:N \l_@@_vars_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {
%     \l_@@_tmp_clist  ,
%     \l_@@_tmp_dim    ,
%     \l_@@_tmp_int    ,
%     \l_@@_tmp_muskip ,
%     \l_@@_tmp_skip   ,
%     \l_@@_tmp_tl
%  }
%   Scratch space.
%    \begin{macrocode}
\clist_new:N \l_@@_tmp_clist
\dim_new:N \l_@@_tmp_dim
\int_new:N \l_@@_tmp_int
\muskip_new:N \l_@@_tmp_muskip
\skip_new:N \l_@@_tmp_skip
\tl_new:N \l_@@_tmp_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\s_@@_mark, \s_@@_stop}
%   Internal scan marks.
%    \begin{macrocode}
\scan_new:N \s_@@_mark
\scan_new:N \s_@@_stop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\q_@@_nil}
%   Internal quarks.
%    \begin{macrocode}
\quark_new:N \q_@@_nil
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[pTF]{\@@_quark_if_nil:n}
%   Branching quark conditional.
%    \begin{macrocode}
\__kernel_quark_new_conditional:Nn \@@_quark_if_nil:N { F }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Testing existence and validity}
%
% There are a number of checks needed for either the existence of
% a type, template or instance. There are also some for the
% validity of a particular call. All of these are collected up here.
%
% \begin{macro}{\@@_execute_if_arg_agree:nnT}
%   A test agreement between the number of arguments for the template
%   type and that specified when creating a template. This is not done as a
%   separate conditional for efficiency and better error message
%    \begin{macrocode}
\cs_new_protected:Npn \@@_execute_if_arg_agree:nnT #1#2#3
  {
    \prop_get:NnN \g_@@_type_prop {#1} \l_@@_tmp_tl
    \int_compare:nNnTF {#2} = \l_@@_tmp_tl
       {#3}
       {
         \msg_error:nneee { template } { argument-number-mismatch }
           {#1} { \l_@@_tmp_tl } {#2}
       }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_execute_if_code_exist:nnT}
%   A template is only fully declared if the code has been set up,
%   which can be checked by looking for the template function itself.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_execute_if_code_exist:nnT #1#2#3
  {
    \cs_if_exist:cTF { \c_@@_code_root_tl #1 / #2 }
      {#3}
      { \msg_error:nnnn { template } { no-template-code } {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {\@@_execute_if_keytype_exist:nT, \@@_execute_if_keytype_exist:VT}
%   The test for valid keytypes looks for a function to set up the key,
%   which is part of the \enquote{code} side of the template definition.
%   This avoids having different lists for the two parts of the process.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_execute_if_keytype_exist:nT #1#2
  {
    \cs_if_exist:cTF { @@_store_value_ #1 :n }
      {#2}
      { \msg_error:nnn { template } { unknown-keytype } {#1} }
  }
\cs_generate_variant:Nn \@@_execute_if_keytype_exist:nT { V }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_execute_if_type_exist:nT}
%   To check that a particular type is valid.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_execute_if_type_exist:nT #1#2
  {
    \prop_if_in:NnTF \g_@@_type_prop {#1}
      {#2}
      { \msg_error:nnn { template } { unknown-type } {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_execute_if_keys_exist:nnT}
%   To check that the keys for a template have been set up before trying
%   to create any code, a simple check for the correctly-named keytype
%   property list.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_if_keys_exist:nnT #1#2#3
  {
    \cs_if_exist:cTF { \c_@@_keytypes_root_tl #1 / #2 }
      {#3}
      { \msg_error:nnnn { template } { unknown-template } {#1} {#2} }
   }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF]{\@@_if_key_value:n, \@@_if_key_value:V}
%   Tests for the first token in a string being \cs{KeyValue}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_key_value:n #1 { T , F , TF }
  {
    \str_if_eq:noTF { \KeyValue } { \tl_head:w #1 \q_nil \q_stop }
      \prg_return_true:
      \prg_return_false:
  }
\prg_generate_conditional_variant:Nnn \@@_if_key_value:n { V } { T , F , TF }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF]{\@@_if_instance_exist:nn}
%   Testing for an instance
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_instance_exist:nn #1#2 { T, F, TF }
  {
    \cs_if_exist:cTF { \c_@@_instances_root_tl #1 / #2 }
      \prg_return_true:
      \prg_return_false:
 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_if_use_template:nTF}
%   Tests for the first token in a string being \cs{UseTemplate}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_use_template:n #1 { TF }
  {
    \str_if_eq:noTF { \UseTemplate } { \tl_head:w #1 \q_nil \q_stop }
      \prg_return_true:
      \prg_return_false:
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Saving and recovering property lists}
%
% The various property lists for templates have to be shuffled in
% and out of storage.
%
% \begin{macro}
%   {
%     \@@_store_defaults:nn ,
%     \@@_store_keytypes:nn ,
%     \@@_store_values:nn   ,
%     \@@_store_vars:nn
%   }
%   The defaults and keytypes are transferred from the scratch property
%   lists to the \enquote{proper} lists for the template being created.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_store_defaults:nn #1#2
  {
    \debug_suspend:
    \prop_gclear_new:c { \c_@@_defaults_root_tl #1 / #2  }
    \prop_gset_eq:cN { \c_@@_defaults_root_tl #1 / #2 }
      \l_@@_values_prop
    \debug_resume:
  }
\cs_new_protected:Npn \@@_store_keytypes:nn #1#2
  {
    \debug_suspend:
    \prop_if_exist:cTF { \c_@@_keytypes_root_tl #1 / #2 }
      {
        \msg_info:nnnn { template } { declare-template-interface } {#1} {#2}
        \prop_gclear:c { \c_@@_keytypes_root_tl #1 / #2 }
      }
      { \prop_new:c { \c_@@_keytypes_root_tl #1 / #2 } }
    \prop_gset_eq:cN { \c_@@_keytypes_root_tl #1 / #2 }
      \l_@@_keytypes_prop
    \seq_gclear_new:c { \c_@@_key_order_root_tl #1 / #2 }
    \seq_gset_eq:cN { \c_@@_key_order_root_tl #1 / #2 }
      \l_@@_key_order_seq
    \debug_resume:
  }
\cs_new_protected:Npn \@@_store_values:nn #1#2
  {
    \debug_suspend:
    \prop_clear_new:c { \c_@@_values_root_tl #1 / #2 }
    \prop_set_eq:cN { \c_@@_values_root_tl #1 / #2 }
      \l_@@_values_prop
    \debug_resume:
  }
\cs_new_protected:Npn \@@_store_vars:nn #1#2
  {
   \debug_suspend:
    \prop_gclear_new:c { \c_@@_vars_root_tl #1 / #2 }
    \prop_gset_eq:cN { \c_@@_vars_root_tl #1 / #2 }
      \l_@@_vars_prop
    \debug_resume:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_recover_defaults:nn ,
%     \@@_recover_keytypes:nn ,
%     \@@_recover_values:nn   ,
%     \@@_recover_vars:nn
%   }
%   Recovering the stored data for a template is rather less complex
%   than storing it. All that happens is the data is  transferred from
%   the permanent to the scratch storage.  However, we need to check the
%   scratch storage does exist.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_recover_defaults:nn #1#2
  {
    \prop_if_exist:cTF
      { \c_@@_defaults_root_tl #1 / #2 }
      {
        \prop_set_eq:Nc \l_@@_values_prop
          { \c_@@_defaults_root_tl #1 / #2 }
      }
      { \prop_clear:N \l_@@_values_prop }
  }
\cs_new_protected:Npn \@@_recover_keytypes:nn #1#2
  {
    \prop_if_exist:cTF
      { \c_@@_keytypes_root_tl #1 / #2 }
      {
        \prop_set_eq:Nc \l_@@_keytypes_prop
          { \c_@@_keytypes_root_tl #1 / #2 }
      }
      { \prop_clear:N \l_@@_keytypes_prop }
    \seq_if_exist:cTF { \c_@@_key_order_root_tl #1 / #2 }
      {
        \seq_set_eq:Nc \l_@@_key_order_seq
          { \c_@@_key_order_root_tl #1 / #2 }
      }
      { \seq_clear:N \l_@@_key_order_seq }
  }
\cs_new_protected:Npn \@@_recover_values:nn #1#2
  {
    \prop_if_exist:cTF
      { \c_@@_values_root_tl #1 / #2 }
      {
        \prop_set_eq:Nc \l_@@_values_prop
          { \c_@@_values_root_tl #1 / #2 }
      }
      { \prop_clear:N \l_@@_values_prop }
  }
\cs_new_protected:Npn \@@_recover_vars:nn #1#2
  {
    \prop_if_exist:cTF
      { \c_@@_vars_root_tl #1 / #2 }
      {
        \prop_set_eq:Nc \l_@@_vars_prop
          { \c_@@_vars_root_tl #1 / #2 }
      }
      { \prop_clear:N \l_@@_vars_prop }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Creating new template types}
%
% \begin{macro}{\@@_define_type:nn, \@@_declare_type:nn}
%   Although the type is the \enquote{top level} of the template
%   system, it is actually very easy to implement. All that happens is that
%   the number of arguments required is recorded, indexed by the name of the
%   type.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_define_type:nn #1#2
  {
    \prop_if_in:NnTF \g_@@_type_prop {#1}
      { \msg_error:nnn { template } { type-already-defined } {#1} }
      { \@@_declare_type:nn {#1} {#2} }
  }
\cs_new_protected:Npn \@@_declare_type:nn #1#2
  {
    \int_set:Nn \l_@@_tmp_int {#2}
    \int_compare:nTF { 0 <= \l_@@_tmp_int <= 9 }
      {
        \msg_info:nnnV { template } { declare-type }
          {#1} \l_@@_tmp_int
        \prop_gput:NnV \g_@@_type_prop {#1}
          \l_@@_tmp_int
      }
      {
        \msg_error:nnnV { template } { bad-number-of-arguments }
          {#1} \l_@@_tmp_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Design part of template declaration}
%
% The \enquote{design} part of a template declaration defines the general
% behaviour of each key, and possibly a default value. However, it does
% not include the implementation. This means that what happens here is
% the two properties are saved to appropriate lists, which can then
% be used later to recover the information when implementing the keys.
%
% \begin{macro}{\@@_declare_template_keys:nnnn}
%   The main function for the \enquote{design} part of creating a template
%   starts by checking that the type exists and that the number of
%   arguments required agree. If that is all fine, then the two storage
%   areas for defaults and keytypes are initialised. The mechanism is then
%   set up for the \pkg{l3keys} module to actually parse the keys.
%   Finally, the code hands of to the storage routine to save the parsed
%   information properly.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_template_keys:nnnn #1#2#3#4
  {
    \@@_execute_if_type_exist:nT {#1}
      {
        \@@_execute_if_arg_agree:nnT {#1} {#3}
          {
            \prop_clear:N \l_@@_values_prop
            \prop_clear:N \l_@@_keytypes_prop
            \seq_clear:N \l_@@_key_order_seq
            \keyval_parse:NNn
              \@@_parse_keys_elt:n \@@_parse_keys_elt:nn {#4}
            \@@_store_defaults:nn {#1} {#2}
            \@@_store_keytypes:nn {#1} {#2}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_keys_elt:n}
% \begin{macro}{\@@_parse_keys_elt_aux:n}
% \begin{macro}{\@@_parse_keys_elt_aux:}
%   Processing the key part of the key--value pair is always carried out
%   using this function, even if a value was found. First, the key name
%   is separated from the keytype, and if necessary the keytype is
%   separated into two parts. This information is then used to check that
%   the keytype is valid, before storing the keytype (plus argument if
%   necessary) as a property of the key name. The key name is also stored
%   (in braces) in the token list to record the order the keys are defined
%   in.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_keys_elt:n #1
  {
    \@@_split_keytype:n {#1}
    \bool_if:NF \l_@@_error_bool
      {
        \@@_execute_if_keytype_exist:VT \l_@@_keytype_tl
          {
            \seq_map_function:NN \c_@@_keytypes_arg_seq
              \@@_parse_keys_elt_aux:n
            \bool_if:NF \l_@@_error_bool
              {
                \seq_if_in:NoTF \l_@@_key_order_seq
                  \l_@@_key_name_tl
                  {
                    \msg_error:nnV { template } { duplicate-key-interface }
                      \l_@@_key_name_tl
                  }
                  { \@@_parse_keys_elt_aux: }
              }
          }
      }
  }
\cs_new_protected:Npn \@@_parse_keys_elt_aux:n #1
  {
    \str_if_eq:VnT \l_@@_keytype_tl {#1}
      {
        \tl_if_empty:NT \l_@@_keytype_arg_tl
          {
            \msg_error:nnn { template } { keytype-requires-argument } {#1}
            \bool_set_true:N \l_@@_error_bool
            \seq_map_break:
          }
      }
  }
\cs_new_protected:Npn \@@_parse_keys_elt_aux:
  {
    \tl_set:Ne \l_@@_tmp_tl
      {
        \l_@@_keytype_tl
        \tl_if_empty:NF \l_@@_keytype_arg_tl
          { { \l_@@_keytype_arg_tl } }
      }
    \prop_put:NVV \l_@@_keytypes_prop \l_@@_key_name_tl
      \l_@@_tmp_tl
    \seq_put_right:NV \l_@@_key_order_seq \l_@@_key_name_tl
    \str_if_eq:VnT \l_@@_keytype_tl { choice }
      {
        \clist_if_in:NnT \l_@@_keytype_arg_tl { unknown }
          { \msg_error:nn { template } { choice-unknown-reserved } }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_parse_keys_elt:nn}
%   For keys which have a default, the keytype and key name are first
%   separated out by the \cs{@@_parse_keys_elt:n}
%   routine, before storing the default value in the scratch property list.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_keys_elt:nn #1#2
  {
    \@@_parse_keys_elt:n {#1}
    \use:c { @@_store_value_ \l_@@_keytype_tl :n } {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_split_keytype:n}
% \begin{macro}{\@@_split_keytype_aux:w}
%   The keytype and key name should be separated by |:|. As the
%   definition might be given inside or outside of a code block,
%   the category code of colons is standardised. After
%   that, the standard delimited argument method is used to separate the
%   two parts.
%    \begin{macrocode}
\cs_new_protected:Npe \@@_split_keytype:n #1
  {
    \exp_not:N \bool_set_false:N \exp_not:N \l_@@_error_bool
    \tl_set:Nn \exp_not:N \l_@@_tmp_tl {#1}
    \tl_replace_all:Nnn \exp_not:N \l_@@_tmp_tl { : } { \token_to_str:N : }
    \tl_if_in:VnTF \exp_not:N \l_@@_tmp_tl { \token_to_str:N : }
      {
        \exp_not:n
          {
            \tl_clear:N \l_@@_key_name_tl
            \exp_after:wN \@@_split_keytype_aux:w
              \l_@@_tmp_tl \s_@@_stop
          }
      }
      {
        \exp_not:N \bool_set_true:N \exp_not:N \l_@@_error_bool
        \msg_error:nnn { template } { missing-keytype } {#1}
      }
  }
\use:e
  {
    \cs_new_protected:Npn \exp_not:N \@@_split_keytype_aux:w
      #1 \token_to_str:N : #2 \s_@@_stop
      {
        \tl_put_right:Ne \exp_not:N \l_@@_key_name_tl
          {
            \exp_not:N \tl_trim_spaces:e
              { \exp_not:N \tl_to_str:n {#1} }
          }
        \tl_if_in:nnTF {#2} { \token_to_str:N : }
          {
            \tl_put_right:Nn \exp_not:N \l_@@_key_name_tl
              { \token_to_str:N : }
            \exp_not:N \@@_split_keytype_aux:w #2 \s_@@_stop
          }
          {
            \exp_not:N \tl_if_empty:NTF \exp_not:N \l_@@_key_name_tl
              {
                \msg_error:nnn { template } { empty-key-name }
                  { \token_to_str:N : #2 }
              }
              { \exp_not:N \@@_split_keytype_arg:n {#2} }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_split_keytype_arg:n, \@@_split_keytype_arg:V}
% \begin{macro}{\@@_split_keytype_arg_aux:n}
% \begin{macro}{\@@_split_keytype_arg_aux:w}
%   The second stage of sorting out the keytype is to check for an
%   argument. As there is no convenient delimiting token to look for,
%   a check is made instead for each possible text value for the keytype.
%   To keep things faster, this only involves the keytypes that need an
%   argument. If a match is made, then a check is also needed to see that
%   it is at the start of the keytype information. All being well, the
%   split can then be applied. Any non-matching keytypes are assumed to
%   be \enquote{correct} as given, and are left alone (this is checked by
%   other code).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_split_keytype_arg:n #1
  {
    \tl_set:Ne \l_@@_keytype_tl { \tl_trim_spaces:n {#1} }
    \tl_clear:N \l_@@_keytype_arg_tl
    \cs_set_protected:Npn \@@_split_keytype_arg_aux:n ##1
      {
        \tl_if_in:nnT {#1} {##1}
          {
            \cs_set:Npn \@@_split_keytype_arg_aux:w
              ####1 ##1 ####2 \s_@@_stop
              {
                \tl_if_blank:nT {####1}
                  {
                    \tl_set:Ne \l_@@_keytype_tl
                      { \tl_trim_spaces:n {##1} }
                    \tl_if_blank:nF {####2}
                      {
                        \tl_set:Ne \l_@@_keytype_arg_tl
                          { \use:n ####2 }
                      }
                    \seq_map_break:
                  }
              }
            \@@_split_keytype_arg_aux:w #1 \s_@@_stop
          }
      }
    \seq_map_function:NN \c_@@_keytypes_arg_seq
      \@@_split_keytype_arg_aux:n
  }
\cs_generate_variant:Nn \@@_split_keytype_arg:n { V }
\cs_new:Npn \@@_split_keytype_arg_aux:n #1 { }
\cs_new:Npn \@@_split_keytype_arg_aux:w #1 \s_@@_stop { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsubsection{Storing values}
%
% As \pkg{lttemplates} pre-processes key values for efficiency reasons,
% there is a need to convert the values given as defaults into
% \enquote{ready to use} data. The same general idea is true when an instance
% is declared. However, assignments are not made until an instance is
% used, and so there has to be some intermediate storage. Furthermore,
% the ability to delay evaluation of results is needed. To achieve these
% aims, a series of \enquote{process and store} functions are defined here.
%
% All of the information about the key (the key name and the keytype)
% is already stored as variables. The same property list is always used
% to store the data, meaning that the only argument required is the
% value to be processed and potentially stored.
%
% \begin{macro}{\@@_store_value_boolean:n}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_store_value_boolean:n #1
  { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_store_value:n, \@@_store_value_choice:n,
%   \@@_store_value_function:n, \@@_store_value_instance:n}
%   With no need to worry about delayed evaluation, these keytypes all
%   just store the input directly.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_store_value:n #1
  { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#1} }
\cs_new_eq:NN \@@_store_value_choice:n    \@@_store_value:n
\cs_new_eq:NN \@@_store_value_function:n  \@@_store_value:n
\cs_new_eq:NN \@@_store_value_instance:n  \@@_store_value:n
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_store_value_aux:Nn, \@@_store_value_integer:n,
%   \@@_store_value_length:n, \@@_store_value_muskip:n,
%   \@@_store_value_real:n, \@@_store_value_skip:n,
%   \@@_store_value_tokenlist:n, \@@_store_value_commalist:n}
%   Storing values in \cs{l_@@_values_prop} is in most cases the same.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_store_value_aux:Nn #1#2
  { \prop_put:Non \l_@@_values_prop \l_@@_key_name_tl {#2} }
\cs_new_protected:Npn \@@_store_value_integer:n
  { \@@_store_value_aux:Nn \int_eval:n }
\cs_new_protected:Npn \@@_store_value_length:n
  { \@@_store_value_aux:Nn \dim_eval:n }
\cs_new_protected:Npn \@@_store_value_muskip:n
  { \@@_store_value_aux:Nn \muskip_eval:n }
\cs_new_protected:Npn \@@_store_value_real:n
  { \@@_store_value_aux:Nn \fp_eval:n }
\cs_new_protected:Npn \@@_store_value_skip:n
  { \@@_store_value_aux:Nn \skip_eval:n }
\cs_new_protected:Npn \@@_store_value_tokenlist:n
  { \@@_store_value_aux:Nn \use:n }
\cs_new_eq:NN \@@_store_value_commalist:n \@@_store_value_tokenlist:n
%    \end{macrocode}
% \end{macro}
%
% \subsection{Implementation part of template declaration}
%
% \begin{macro}{\@@_declare_template_code:nnnnn}
% \changes{2025-01-20}{v1.0e}{Speed up test for \cs{AssignTemplateKeys}}
% \begin{macro}{\@@_declare_template_code:nnnn}
%   The main function for implementing a template starts with a couple of
%   simple checks to make sure that there are no obvious mistakes: the
%   number of arguments must agree and the template keys must have been
%   declared.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_template_code:nnnnn #1#2#3#4#5
  {
    \@@_execute_if_type_exist:nT {#1}
      {
        \@@_execute_if_arg_agree:nnT {#1} {#3}
          {
            \@@_if_keys_exist:nnT {#1} {#2}
              {
                \@@_store_key_implementation:nnn {#1} {#2} {#4}
                \str_if_in:nnTF {#5} { AssignTemplateKeys }
                  {
                    \regex_match:nnTF { \c { AssignTemplateKeys } } {#5}
                      { \@@_declare_template_code:nnnn {#1} {#2} {#3} {#5} }
                      {
                        \@@_declare_template_code:nnnn
                          {#1} {#2} {#3} { \AssignTemplateKeys #5 }
                      }
                  }
                  {
                    \@@_declare_template_code:nnnn
                      {#1} {#2} {#3} { \AssignTemplateKeys #5 }
                  }
              }
           }
      }
   }
\cs_new_protected:Npn \@@_declare_template_code:nnnn #1#2#3#4
  {
    \cs_if_exist:cT { \c_@@_code_root_tl #1 / #2 }
      { \msg_info:nnnn { template } { declare-template-code } {#1} {#2} }
    \cs_generate_from_arg_count:cNnn
      { \c_@@_code_root_tl #1 / #2 }
      \cs_gset_protected:Npn {#3} {#4}
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_store_key_implementation:nnn}
%   Actually storing the implementation part of a template is quite easy
%   as it only requires the list of keys given to be turned into a
%   property list. There is also some error-checking to do, hence the need
%   to have the list of defined keytypes available. In certain cases
%   (when choices are involved) parsing the key results in changes to the
%   default values. That is why they are loaded and then saved again.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_store_key_implementation:nnn #1#2#3
  {
    \@@_recover_defaults:nn {#1} {#2}
    \@@_recover_keytypes:nn {#1} {#2}
    \prop_clear:N \l_@@_vars_prop
    \keyval_parse:nnn
      { \@@_parse_vars_elt:n } { \@@_parse_vars_elt:nnn { #1 / #2 } } {#3}
    \@@_store_vars:nn {#1} {#2}
    \prop_map_inline:Nn \l_@@_keytypes_prop
      { \msg_error:nnnnn { template } { key-not-implemented } {##1} {#2} {#1} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_vars_elt:n}
%   At the implementation stage, every key must have a value given. So
%   this is an error function.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_vars_elt:n #1
  { \msg_error:nnn { template } { key-no-variable } {#1} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_vars_elt:nnn}
% \begin{macro}{\@@_parse_vars_elt_aux:nn}
% \begin{macro}{\@@_parse_vars_elt_aux:nw}
% \begin{macro}{\@@_parse_vars_elt_aux:nnn, \@@_parse_vars_elt_aux:nne}
% \begin{macro}{\@@_parse_vars_elt_key:nn}
%   The actual storage part here is very simple: the storage bin name
%   is placed into the property list. At the same time, a comparison is
%   made with the keytypes defined earlier: if there is a mismatch then
%   an error is raised.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_vars_elt:nnn #1#2#3
 {
    \tl_set:Ne \l_@@_key_name_tl
      { \tl_trim_spaces:e { \tl_to_str:n {#2} } }
    \prop_get:NVNTF \l_@@_keytypes_prop
      \l_@@_key_name_tl
      \l_@@_keytype_tl
      {
        \@@_split_keytype_arg:V \l_@@_keytype_tl
        \@@_parse_vars_elt_aux:nn {#1} {#3}
        \prop_remove:NV \l_@@_keytypes_prop \l_@@_key_name_tl
      }
      { \msg_error:nnn { template } { unknown-key } {#2} }
  }
%    \end{macrocode}
%   Split off any leading \texttt{global} and they look for the way to
%   implement.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_vars_elt_aux:nn #1#2
  {
    \@@_parse_vars_elt_aux:nw {#1} #2 global global \s_@@_stop
  }
\cs_new_protected:Npn \@@_parse_vars_elt_aux:nw
  #1#2 global #3 global #4 \s_@@_stop
  {
    \tl_if_blank:nTF {#4}
      { \@@_parse_vars_elt_aux:nnn {#1} { } {#2} }
      {
        \tl_if_blank:nTF {#2}
          {
            \@@_parse_vars_elt_aux:nne
              {#1} { global } { \tl_trim_spaces:n {#3} }
          }
          { \msg_error:nnn { template } { bad-variable } { #2 global #3 } }
      }
  }
\cs_new_protected:Npn \@@_parse_vars_elt_aux:nnn #1#2#3
  {
    \str_case:VnF \l_@@_keytype_tl
      {
        { choice } { \@@_implement_choices:nn {#1} {#3} }
        { function }
          {
            \cs_if_exist:NF #3
              { \cs_new:Npn #3 { } }
            \@@_parse_vars_elt_key:nn {#1}
              {
                .code:n =
                  {
                    \cs_generate_from_arg_count:NNnn
                      \exp_not:N #3
                      \exp_not:c
                        { cs_ \str_if_eq:nnT {#1} { global } { g } set:Npn }
                      { \exp_not:V \l_@@_keytype_arg_tl }
                      {##1}
                  }
              }
            \prop_put:NVn \l_@@_vars_prop
              \l_@@_key_name_tl {#2#3}
          }
        { instance }
          {
            \@@_parse_vars_elt_key:nn {#1}
              {
                .code:n =
                  {
                    \exp_not:c
                      { cs_ \str_if_eq:nnT {#1} { global } { g } set:Npn }
                      \exp_not:N #3 { \UseInstance {##1} }
                  }
              }
            \prop_put:NVn \l_@@_vars_prop
              \l_@@_key_name_tl {#2#3}
          }
      }
      {
        \tl_if_single:nTF {#3}
          {
            \cs_if_exist:NF #3
              { \use:c { \@@_map_var_type: _new:N } #3 }
            \@@_parse_vars_elt_key:nn {#1}
              {
                . \@@_map_var_type:
                  _ \str_if_eq:nnT {#1} { global } { g } set:N
                    = \exp_not:N #3
              }
            \prop_put:NVn \l_@@_vars_prop
              \l_@@_key_name_tl {#2#3}
          }
          { \msg_error:nnn { template } { bad-variable } {#2#3} }
      }
  }
\cs_generate_variant:Nn \@@_parse_vars_elt_aux:nnn { nne }
\cs_new_protected:Npn \@@_parse_vars_elt_key:nn #1#2
  {
    \keys_define:ne { template / #1 }
      { \l_@@_key_name_tl #2 }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_map_var_type:}
%   Turn a \enquote{friendly} variable type into an \texttt{expl3} one.
%    \begin{macrocode}
\cs_new:Npn \@@_map_var_type:
  {
    \str_case:Vn \l_@@_keytype_tl
      {
        { boolean }   { bool }
        { commalist } { clist }
        { integer }   { int }
        { length }    { dim }
        { muskip }    { muskip }
        { real }      { fp }
        { skip }      { skip }
        { tokenlist } { tl }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_implement_choices:nn}
% \begin{macro}{\@@_implement_choices_default:}
%   Implementing choices requires a second key--value loop. So after a
%   little set-up, the standard parser is called.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_implement_choices:nn #1#2
  {
    \clist_set:NV \l_@@_tmp_clist \l_@@_keytype_arg_tl
    \prop_put:NVn \l_@@_vars_prop \l_@@_key_name_tl { }
    \keys_define:ne { template / #1 } { \l_@@_key_name_tl .choice: }
    \keyval_parse:nnn
      { \@@_implement_choice_elt:n }
      { \@@_implement_choice_elt:nnn {#1} }
      {#2}
    \prop_get:NVNT \l_@@_values_prop \l_@@_key_name_tl
      \l_@@_tmp_tl
      { \@@_implement_choices_default: }
    \clist_if_empty:NF \l_@@_tmp_clist
      {
        \clist_map_inline:Nn \l_@@_tmp_clist
          { \msg_error:nnn { template } { choice-not-implemented } {##1} }
      }
  }
%    \end{macrocode}
%   A sanity check for the default value, so that an error is raised
%   now and not when converting to assignments.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_implement_choices_default:
  {
    \tl_set:Ne \l_@@_tmp_tl
      { \l_@@_key_name_tl \c_space_tl \l_@@_tmp_tl }
    \prop_if_in:NVF \l_@@_vars_prop \l_@@_tmp_tl
      {
        \tl_set:Ne \l_@@_tmp_tl
          { \l_@@_key_name_tl \c_space_tl \l_@@_tmp_tl }
        \prop_if_in:NVF \l_@@_vars_prop \l_@@_tmp_tl
          {
            \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
              \l_@@_tmp_tl
            \@@_split_keytype_arg:V \l_@@_tmp_tl
            \prop_get:NVN \l_@@_values_prop \l_@@_key_name_tl
              \l_@@_tmp_tl
            \msg_error:nnVV { template } { unknown-default-choice }
              \l_@@_key_name_tl
              \l_@@_key_name_tl
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_implement_choice_elt:nnn, \@@_implement_choice_elt_aux:nnn}
% \begin{macro}{\@@_implement_choice_elt_aux:n}
% \begin{macro}{\@@_implement_choice_elt:n}
%   The actual storage of the implementation of a choice is mainly about
%   error checking. The code here ensures that all choices have to have
%   been declared, apart from the special \texttt{unknown} choice, which
%   must come last. The code for each choice is stored along with the
%   key name in the variables property list.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_implement_choice_elt:nnn #1#2#3
  {
    \clist_if_empty:NTF \l_@@_tmp_clist
      {
        \str_if_eq:nnTF {#2} { unknown }
          { \@@_implement_choice_elt_aux:nnn {#1} {#2} {#3} }
          { \@@_implement_choice_elt_aux:n {#2} }
      }
      {
        \clist_if_in:NnTF \l_@@_tmp_clist {#2}
          {
            \clist_remove_all:Nn \l_@@_tmp_clist {#2}
            \@@_implement_choice_elt_aux:nnn {#1} {#2} {#3}
          }
          { \@@_implement_choice_elt_aux:n {#2} }
      }
  }
\cs_new_protected:Npn \@@_implement_choice_elt_aux:n #1
  {
    \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
      \l_@@_tmp_tl
    \@@_split_keytype_arg:V \l_@@_tmp_tl
    \msg_error:nnVn { template } { unknown-choice } \l_@@_key_name_tl {#1}
  }
\cs_new_protected:Npn \@@_implement_choice_elt_aux:nnn #1#2#3
  {
    \keys_define:ne { template / #1 }
      { \l_@@_key_name_tl / #2 .code:n = { \exp_not:n {#3} } }
    \tl_set:Ne \l_@@_tmp_tl
      { \l_@@_key_name_tl \c_space_tl #2 }
    \prop_put:NVn \l_@@_vars_prop \l_@@_tmp_tl {#3}
  }
\cs_new_protected:Npn \@@_implement_choice_elt:n #1
  {
    \msg_error:nnVn { template } { choice-requires-code }
      \l_@@_key_name_tl {#1}
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Editing template defaults}
%
% \begin{macro}{\@@_edit_defaults:nnn}
%   Editing the template defaults means getting the values back out
%   of the store, then parsing the list of new values before putting
%   the updated list back into storage.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_edit_defaults:nnn #1#2#3
  {
    \@@_if_keys_exist:nnT {#1} {#2}
      {
        \@@_recover_defaults:nn {#1} {#2}
        \@@_parse_values:nnn {#1} {#2} {#3}
        \@@_store_defaults:nn {#1} {#2}
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_values:nnn}
%   The routine to parse values is the same for both editing a
%   template and setting up an instance. So the code here does only the
%   minimum necessary for reading the values.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_values:nnn #1#2#3
  {
    \@@_recover_keytypes:nn {#1} {#2}
    \keyval_parse:NNn
      \@@_parse_values_elt:n \@@_parse_values_elt:nn {#3}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_values_elt:n}
%   Every key needs a value, so this is just an error routine.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_values_elt:n #1
  {
    \bool_set_true:N \l_@@_error_bool
    \msg_error:nnn { template } { key-no-value } {#1}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_parse_values_elt:nn}
% \begin{macro}{\@@_parse_values_elt_aux:w}
% \changes{2025-07-08}{v1.0f}{New macro}
% \begin{macro}{\@@_parse_values_elt_aux:n}
% \changes{2025-07-08}{v1.0f}{Allow for value expansion}
% \begin{macro}
%   {
%     \@@_parse_values_exp:n, \@@_parse_values_exp:o,
%     \@@_parse_values_exp:V, \@@_parse_values_exp:v,
%     \@@_parse_values_exp:e
%   }
% \changes{2025-07-08}{v1.0f}{New macro}
% \begin{macro}{\@@_parse_values_exp:N, \@@_parse_values_exp:c}
% \changes{2025-07-08}{v1.0f}{New macro}
%   To store the value, find the keytype then call the saving function.
%   These need the current key name, stored in \cs{l_@@_key_name_tl}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_parse_values_elt:nn #1#2
  {
    \use:e
      {
        \@@_parse_values_elt_aux:w
          \tl_trim_spaces:e { \tl_to_str:n { #1 : n : } }
          \exp_not:N \q_stop
      }
    \prop_get:NVNTF \l_@@_keytypes_prop \l_@@_key_name_tl
      \l_@@_tmp_tl
      { \@@_parse_values_elt_aux:n {#2} }
      { \msg_error:nnV { template } { unknown-key } \l_@@_key_name_tl }
  }
\use:e
  {
    \cs_new_protected:Npn \exp_not:N \@@_parse_values_elt_aux:w
      #1 \token_to_str:N : #2 \token_to_str:N : #3 \exp_not:N \q_stop
  }
    {
      \tl_set:Nn \l_@@_key_name_tl {#1}
      \str_set:Nn \l_@@_value_exp_str {#2}
    }
\cs_new_protected:Npn \@@_parse_values_elt_aux:n #1
  {
    \@@_split_keytype_arg:V \l_@@_tmp_tl
    \cs_if_exist_use:cF { @@_parse_values_exp: \l_@@_value_exp_str }
      {
        \msg_error:nnV { template } { unknown-expansion } \l_@@_value_exp_str
        \use_none:n
      }
        {#1}
  }
\cs_new_protected:Npn \@@_parse_values_exp:n #1
  { \use:c { @@_store_value_ \l_@@_keytype_tl :n } {#1} }
\cs_generate_variant:Nn \@@_parse_values_exp:n { o , V , v , e }
\cs_new_eq:NN \@@_parse_values_exp:N \@@_parse_values_exp:n
\cs_generate_variant:Nn \@@_parse_values_exp:N  { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_template_set_eq:nnn}
%   To copy a template, each of the lists plus the code has to be copied
%   across. To keep this independent of the list storage system, it is
%   all done with two-part shuffles.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_template_set_eq:nnn #1#2#3
  {
    \@@_recover_defaults:nn {#1} {#3}
    \@@_store_defaults:nn {#1} {#2}
    \@@_recover_keytypes:nn {#1} {#3}
    \@@_store_keytypes:nn {#1} {#2}
    \@@_recover_vars:nn {#1} {#3}
    \@@_store_vars:nn {#1} {#2}
    \cs_if_exist:cT { \c_@@_code_root_tl #1 / #2 }
      { \msg_info:nnnn { template } { declare-template-code } {#1} {#2} }
    \cs_gset_eq:cc { \c_@@_code_root_tl #1 / #2 }
      { \c_@@_code_root_tl #1 / #3 }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Creating instances of templates}
%
% \begin{macro}
%   {
%     \@@_declare_instance:nnnn,
%     \@@_declare_instance_aux:nnnn
%   }
%   Making an instance has two distinct parts. First, the keys given are
%   parsed to transfer the values into the structured data format used
%   internally. This allows the default and given values to be combined
%   with no repetition. In the second step, the structured data is
%   converted to pre-defined variable assignments, and these are stored
%   in the function for the instance.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_declare_instance:nnnn #1#2#3#4
  {
    \@@_execute_if_code_exist:nnT {#1} {#2}
      {
        \@@_recover_defaults:nn {#1} {#2}
        \@@_recover_vars:nn {#1} {#2}
        \@@_declare_instance_aux:nnnn {#1} {#2} {#3} {#4}
      }
  }
\cs_new_protected:Npn \@@_declare_instance_aux:nnnn #1#2#3#4
  {
    \bool_set_false:N \l_@@_error_bool
    \@@_parse_values:nnn {#1} {#2} {#4}
    \bool_if:NF \l_@@_error_bool
      {
        \prop_put:Nnn \l_@@_values_prop { from~template } {#2}
        \@@_store_values:nn {#1} {#3}
        \@@_convert_to_assignments:
        \cs_if_exist:cT { \c_@@_instances_root_tl #1 / #3 }
          { \msg_info:nnnn { template } { declare-instance } {#3} {#1} }
        \cs_set_protected:cpe { \c_@@_instances_root_tl #1 / #3 }
          {
            \exp_not:N \@@_assignments_push:n
              { \exp_not:V \l_@@_assignments_tl }
            \exp_not:c { \c_@@_code_root_tl #1 / #2 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_instance_set_eq:nnn}
%   Copy--paste an instance.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_instance_set_eq:nnn #1#2#3
  {
    \@@_if_instance_exist:nnTF {#1} {#3}
      {
        \@@_recover_values:nn {#1} {#3}
        \@@_store_values:nn {#1} {#2}
        \cs_if_exist:cT { \c_@@_instances_root_tl #1 / #2 }
          { \msg_info:nnnn { template } { declare-instance } {#2} {#1} }
        \cs_set_eq:cc { \c_@@_instances_root_tl #1 / #2 }
          { \c_@@_instances_root_tl #1 / #3 }
      }
      { \msg_error:nnnn { template } { unknown-instance } {#1} {#3} }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_edit_instance:nnn}
% \begin{macro}
%   {\@@_edit_instance_aux:nnnnn, \@@_edit_instance_aux:nVnnn}
%   Editing an instance is almost identical to declaring one. The only
%   variation is the source of the values to use. When editing, they are
%   recovered from the previous instance run.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_edit_instance:nnn #1#2#3
  {
    \@@_if_instance_exist:nnTF {#1} {#2}
      {
        \@@_recover_values:nn {#1}  {#2}
        \prop_get:NnN \l_@@_values_prop { from~template }
          \l_@@_tmp_tl
        \@@_edit_instance_aux:nVnn
          {#1} \l_@@_tmp_tl {#2} {#3}
      }
      { \msg_error:nnnn { template } { unknown-instance } {#1} {#2} }
  }
\cs_new_protected:Npn \@@_edit_instance_aux:nnnn #1#2#3#4
  {
    \@@_recover_vars:nn {#1} {#2}
    \@@_declare_instance_aux:nnnn {#1} {#2} {#3} {#4}
  }
\cs_generate_variant:Nn \@@_edit_instance_aux:nnnn { nV }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_convert_to_assignments:}
% \begin{macro}{\@@_convert_to_assignments_aux:n}
% \begin{macro}
%   {\@@_convert_to_assignments_aux:nn, \@@_convert_to_assignments_aux:nV}
%   The idea on converting to a set of assignments is to loop over each
%   key, so that the loop order follows the declaration order of the keys.
%   This is done using a sequence as property lists are not
%   \enquote{ordered}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_convert_to_assignments:
  {
    \tl_clear:N \l_@@_assignments_tl
    \seq_map_function:NN \l_@@_key_order_seq
      \@@_convert_to_assignments_aux:n
  }
\cs_new_protected:Npn \@@_convert_to_assignments_aux:n #1
  {
    \prop_get:NnN \l_@@_keytypes_prop {#1} \l_@@_tmp_tl
    \@@_convert_to_assignments_aux:nV {#1} \l_@@_tmp_tl
  }
%    \end{macrocode}
%   The second auxiliary function actually does the work. The
%   arguments here are the key name (|#1|) and the keytype (|#2|).
%   From those, the value to assign and the name of the appropriate
%   variable are recovered. A bit of work is then needed to sort out
%   keytypes with arguments (for example instances), and to look for
%   global assignments. Once that is done, a hand-off can be made to the
%   handler for the relevant keytype.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_convert_to_assignments_aux:nn #1#2
  {
    \prop_get:NnNT \l_@@_values_prop {#1} \l_@@_value_tl
      {
        \prop_get:NnNTF \l_@@_vars_prop {#1} \l_@@_var_tl
          {
            \@@_split_keytype_arg:n {#2}
            \str_if_eq:VnF \l_@@_keytype_tl { choice }
              {
                \str_if_eq:VnF \l_@@_keytype_tl { code }
                  { \@@_find_global: }
              }
            \tl_set:Nn \l_@@_key_name_tl {#1}
            \cs_if_exist_use:cF { @@_assign_ \l_@@_keytype_tl : }
              { \@@_assign_variable: }
          }
          { \msg_error:nnn { template } { unknown-attribute } {#1} }
      }
  }
\cs_generate_variant:Nn \@@_convert_to_assignments_aux:nn { nV }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_find_global:}
% \begin{macro}{\@@_find_global_aux:w}
%   Global assignments should have the phrase |global| at the front.
%   This is pretty easy to find: no other error checking, though.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_find_global:
  {
    \bool_set_false:N \l_@@_global_bool
    \tl_if_in:onT \l_@@_var_tl { global }
      {
        \exp_after:wN \@@_find_global_aux:w \l_@@_var_tl \s_@@_stop
      }
  }
\cs_new_protected:Npn \@@_find_global_aux:w  #1 global #2 \s_@@_stop
  {
    \tl_set:Nn \l_@@_var_tl {#2}
    \bool_set_true:N \l_@@_global_bool
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_instance_value:nnn}
% \changes{2025-11-21}{v1.0g}{New function}
%   For editing templates.
%    \begin{macrocode}
\cs_new:Npn \@@_instance_value:nnn #1#2#3
   {
    \@@_if_instance_exist:nnT {#1} {#2}
      { \prop_item:cn { \c_@@_values_root_tl #1 / #2 } {#3} }
   }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Using templates directly}
%
% \begin{macro}{\@@_use_template:nnn}
%   Directly use a template with a particular parameter setting.
%   This is also picked up if used in a nested fashion inside a parameter
%   list. The idea is essentially the same as creating an instance,
%   just with no saving of the result.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_use_template:nnn #1#2#3
  {
    \@@_execute_if_code_exist:nnT {#1} {#2}
      {
        \@@_recover_defaults:nn {#1} {#2}
        \@@_recover_vars:nn {#1} {#2}
        \@@_parse_values:nnn {#1} {#2} {#3}
        \@@_convert_to_assignments:
        \use:c { \c_@@_code_root_tl #1 / #2  }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Assigning values to variables}
%
% \begin{macro}{\@@_assign_boolean:}
% \begin{macro}{\@@_assign_boolean_aux:n}
%   Setting a Boolean value is slightly different to everything else
%   as the value can be used to work out which \texttt{set} function to
%   call. As long as there is no need to recover things from another
%   variable, everything is pretty easy. If there is, then we need to allow
%   for the fact that the recovered value here will \emph{not} be expandable,
%   so needs to be converted to something that is.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_boolean:
  {
    \bool_if:NTF \l_@@_global_bool
      { \@@_assign_boolean_aux:n { bool_gset } }
      { \@@_assign_boolean_aux:n { bool_set } }
  }
\cs_new_protected:Npn \@@_assign_boolean_aux:n #1
  {
    \@@_if_key_value:VTF \l_@@_value_tl
      {
        \@@_key_to_value:
        \tl_put_right:Ne \l_@@_assignments_tl
          {
            \exp_not:c { #1 _eq:NN }
            \exp_not:V \l_@@_var_tl
            \exp_not:V \l_@@_value_tl
          }
      }
      {
        \tl_put_right:Ne \l_@@_assignments_tl
          {
            \exp_not:c { #1 _ \l_@@_value_tl :N }
            \exp_not:V \l_@@_var_tl
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assign_choice:}
% \begin{macro}
%   {\@@_assign_choice_aux:nF, \@@_assign_choice_aux:eF}
%   The idea here is to find either the choice as-given or else the
%   special |unknown| choice, and to copy the appropriate code across.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_choice:
  {
    \@@_assign_choice_aux:eF
      { \l_@@_key_name_tl \c_space_tl \l_@@_value_tl }
      {
        \@@_assign_choice_aux:eF
          { \l_@@_key_name_tl \c_space_tl unknown }
          {
            \prop_get:NVN \l_@@_keytypes_prop \l_@@_key_name_tl
              \l_@@_tmp_tl
            \@@_split_keytype_arg:V \l_@@_tmp_tl
            \msg_error:nnVV { template } { unknown-choice }
              \l_@@_key_name_tl
              \l_@@_value_tl
          }
      }
  }
\cs_new_protected:Npn \@@_assign_choice_aux:nF #1
  {
    \prop_get:NnNTF \l_@@_vars_prop {#1} \l_@@_tmp_tl
      { \tl_put_right:NV \l_@@_assignments_tl \l_@@_tmp_tl }
  }
\cs_generate_variant:Nn \@@_assign_choice_aux:nF { e }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assign_function:}
% \begin{macro}{\@@_assign_function_aux:N}
%   This looks a bit messy but is only actually one function.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_function:
  {
    \bool_if:NTF \l_@@_global_bool
      { \@@_assign_function_aux:N \cs_gset:Npn }
      { \@@_assign_function_aux:N \cs_set:Npn  }
  }
\cs_new_protected:Npn \@@_assign_function_aux:N #1
  {
    \tl_put_right:Ne \l_@@_assignments_tl
      {
        \cs_generate_from_arg_count:NNnn
          \exp_not:V \l_@@_var_tl
          \exp_not:N #1
          { \exp_not:V \l_@@_keytype_arg_tl }
          { \exp_not:V \l_@@_value_tl }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assign_instance:}
% \begin{macro}{\@@_assign_instance_aux:N}
%   Using an instance means adding the appropriate function creation to
%   the tl. No checks are made at this stage, so if the instance is
%   not valid then errors will arise later.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_instance:
  {
    \bool_if:NTF \l_@@_global_bool
      { \@@_assign_instance_aux:N \cs_gset_protected:Npn }
      { \@@_assign_instance_aux:N \cs_set_protected:Npn  }
  }
\cs_new_protected:Npn \@@_assign_instance_aux:N #1
  {
    \tl_put_right:Ne \l_@@_assignments_tl
      {
        \exp_not:N #1 \exp_not:V \l_@@_var_tl
          {
            \@@_use_instance:nn
              { \exp_not:V \l_@@_keytype_arg_tl }
              { \exp_not:V \l_@@_value_tl }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_assign_variable:}
% \changes{2024-10-07}{v1.0d}{Correct passing of \cs{KeyValue} contents}
% \begin{macro}{\@@_assign_variable:n}
%   A general-purpose function for all of the other assignments.
%   As long as the value is not coming from another variable, the stored
%   value is simply transferred for output. We use \texttt{V}-type expansion
%   for the \cs{KeyValue} case: for token lists this is essential, whilst
%   for register-based variables, it does no harm and avoids needing a
%   low-level test.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_variable:
  {
    \exp_args:Ne \@@_assign_variable:n
      {
        \@@_map_var_type:
        _
        \bool_if:NT \l_@@_global_bool { g } 
        set:N
      }
  }
%    \end{macrocode}
%   Notice we need a \texttt{V}-type variant for each \texttt{(g)set}
%   operation here: these need to be provided by \pkg{expl3}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assign_variable:n #1
  {
    \@@_if_key_value:VTF \l_@@_value_tl
      {
        \@@_key_to_value:
        \tl_put_right:Ne \l_@@_assignments_tl
          {
            \exp_not:c { #1 V } \exp_not:V \l_@@_var_tl
             \exp_not:V \l_@@_value_tl
          }
      }
      {
        \tl_put_right:Ne \l_@@_assignments_tl
          {
            \exp_not:c { #1 n } \exp_not:V \l_@@_var_tl
             { \exp_not:V \l_@@_value_tl }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_key_to_value:}
% \begin{macro}{\@@_key_to_value_auxi:w}
% \begin{macro}{\@@_key_to_value_auxii:w}
%   The idea here is to recover the attribute value of another key. To
%   do that, the marker is removed and a look up takes place. If this
%   is successful, then the name of the variable of the attribute is
%   returned. This assumes that the value will be used in context where
%   it will be converted to a value, for example when setting a number.
%   There is also a need to check in case the copied value happens to be
%   \texttt{global}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_key_to_value:
  { \exp_after:wN \@@_key_to_value_auxi:w \l_@@_value_tl }
\cs_new_protected:Npn \@@_key_to_value_auxi:w \KeyValue #1
  {
    \tl_set:Ne \l_@@_tmp_tl { \tl_trim_spaces:e { \tl_to_str:n {#1} } }
    \prop_get:NVNTF \l_@@_vars_prop \l_@@_tmp_tl
      \l_@@_value_tl
      {
        \exp_after:wN \@@_key_to_value_auxii:w \l_@@_value_tl
          \s_@@_mark global \q_@@_nil \s_@@_stop
      }
      { \msg_error:nnV { template } { unknown-attribute } \l_@@_tmp_tl }
  }
\cs_new_protected:Npn \@@_key_to_value_auxii:w #1 global #2#3 \s_@@_stop
  {
    \@@_quark_if_nil:NF #2
      { \tl_set:Nn \l_@@_value_tl {#2} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Using instances}
%
% \begin{macro}{\@@_use_instance:nn}
% \begin{macro}{\@@_use_instance_aux:nNnnn}
% \begin{macro}{\@@_use_instance_aux:nn}
%   Using an instance is just a question of finding the appropriate function.
%   If nothing is found, an error is raised. One complication is that
%   if the first token of argument |#2| is \cs{UseTemplate} then that
%   is also valid. There is an error-test to make sure that the
%   types agree, and if so the template is used directly.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_use_instance:nn #1#2
  {
    \@@_if_use_template:nTF {#2}
      { \@@_use_instance_aux:nNnnn {#1} #2 }
      { \@@_use_instance_aux:nn {#1} {#2} }
  }
\cs_new_protected:Npn \@@_use_instance_aux:nNnnn #1#2#3#4#5
  {
    \str_if_eq:nnTF {#1} {#3}
      { \@@_use_template:nnn {#3} {#4} {#5} }
      { \msg_error:nnnn { template } { type-mismatch } {#1} {#3} }
}
\cs_new_protected:Npn \@@_use_instance_aux:nn #1#2
  {
    \@@_if_instance_exist:nnTF {#1} {#2}
      { \use:c { \c_@@_instances_root_tl #1 / #2 } }
      { \msg_error:nnnn { template } { unknown-instance } {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%\subsection{Assignment manipulation}
%
%  A few functions to transfer assignments about, as this is needed by
%  \cs{AssignTemplateKeys}.
%
% \begin{macro}{\@@_assignments_pop:}
%   To actually use the assignments.
%    \begin{macrocode}
\cs_new:Npn \@@_assignments_pop: { \l_@@_assignments_tl }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_assignments_push:n}
%   Here, the assignments are stored for later use.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_assignments_push:n #1
  { \tl_set:Nn \l_@@_assignments_tl {#1} }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Showing templates and instances}
%
% \begin{macro}{\@@_show_code:nn}
%   Showing the code for a template is just a translation of
%   \cs{cs_show:c}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_show_code:nn #1#2
  { \cs_show:c { \c_@@_code_root_tl #1 / #2 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_show_defaults:nn,
%     \@@_show_keytypes:nn,
%     \@@_show_vars:nn
%   }
% \begin{macro}{\@@_show:Nnnn}
%   A modified version of the property-list printing code, such that
%   the output refers to templates and instances rather than to the
%   underlying structures.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_show_defaults:nn #1#2
  {
    \@@_if_keys_exist:nnT {#1} {#2}
      {
        \@@_recover_defaults:nn {#1} {#2}
        \@@_show:Nnnn \l_@@_values_prop
          {#1} {#2} { default~values }
      }
  }
\cs_new_protected:Npn \@@_show_keytypes:nn #1#2
  {
    \@@_if_keys_exist:nnT {#1} {#2}
      {
        \@@_recover_keytypes:nn {#1} {#2}
        \@@_show:Nnnn \l_@@_keytypes_prop
          {#1} {#2} { interface }
      }
  }
\cs_new_protected:Npn \@@_show_vars:nn #1#2
  {
     \@@_execute_if_code_exist:nnT {#1} {#2}
      {
        \@@_recover_vars:nn {#1} {#2}
        \@@_show:Nnnn \l_@@_vars_prop
          {#1} {#2} { variable~mapping }
      }
  }
\cs_new_protected:Npn \@@_show:Nnnn #1#2#3#4
  {
    \msg_show:nneeee { template } { show-attribute }
      { \tl_to_str:n {#2} }
      { \tl_to_str:n {#3} }
      { \tl_to_str:n {#4} }
      { \prop_map_function:NN #1 \msg_show_item_unbraced:nn }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_show_values:nn}
% \changes{2025-11-21}{v1.0g}{Extend message}
%   Instance values are a little more complex, as is the template to consider.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_show_values:nn #1#2
  {
    \@@_if_instance_exist:nnTF {#1} {#2}
      {
        \@@_recover_values:nn {#1} {#2}
        \msg_show:nneee { template } { show-values }
          { \tl_to_str:n {#1} }
          { \tl_to_str:n {#2} }
          {
            \prop_map_function:NN \l_@@_values_prop
              \msg_show_item_unbraced:nn
          }
      }
      { \msg_info:nnnn { template } { unknown-instance } {#1} {#2} }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Messages}
%
% The text for error messages: short and long text for all of them.
%    \begin{macrocode}
\msg_new:nnnn { template } { argument-number-mismatch }
  { Template~type~'#1'~takes~#2~argument(s). }
  {
    Templates~of~type~'#1'~require~#2~argument(s).\\
    You~have~tried~to~make~a~template~for~'#1'~
    with~#3~argument(s),~which~is~not~possible:~
    the~number~of~arguments~must~agree.
  }
\msg_new:nnnn { template } { bad-number-of-arguments }
  { Bad~number~of~arguments~for~template~type~'#1'. }
  {
    A~template~may~accept~between~0~and~9~arguments.\\
    You~asked~to~use~#2~arguments:~this~is~not~supported.
  }
\msg_new:nnnn { template } { bad-variable }
  { Incorrect~variable~description~'#1'. }
  {
    The~argument~'#1'~is~not~of~the~form \\
    ~~'<variable>'\\
    ~or~\\
    ~~'global~<variable>'.\\
    It~must~be~given~in~one~of~these~formats~to~be~used~in~a~template.
  }
\msg_new:nnnn { template } { choice-not-implemented }
  { The~choice~'#1'~has~no~implementation. }
  {
    Each~choice~listed~in~the~interface~for~a~template~must~
    have~an~implementation.
  }
\msg_new:nnnn { template } { choice-no-code }
  { The~choice~'#1'~requires~implementation~details. }
  {
    When~creating~template~code~using~\DeclareTemplateCode,~
    each~choice~name~must~have~an~associated~implementation.\\
    This~should~be~given~after~a~'='~sign:~LaTeX~did~not~find~one.
  }
\msg_new:nnnn { template } { choice-requires-code }
  { The~choice~'#2'~for~key~'#1'~requires~an~implementation. }
  {
    You~should~have~put:\\
    \ \ #1~:~choice~{~#2 = <code> ~} \\
    but~LaTeX~did~not~find~any~<code>.
  }
\msg_new:nnnn { template } { duplicate-key-interface }
  { Key~'#1'~appears~twice~in~interface~definition~\msg_line_context:. }
  {
    Each~key~can~only~have~one~interface~declared~in~a~template.\\
    LaTeX~found~two~interfaces~for~'#1'.
  }
\msg_new:nnnn { template } { keytype-requires-argument }
  { The~key~type~'#1'~requires~an~argument~\msg_line_context:. }
  {
    You~should~have~put:\\
    \ \ <key-name>~:~#1~{~<argument>~} \\
    but~LaTeX~did~not~find~an~<argument>.
  }
\msg_new:nnnn { template } { invalid-keytype }
  { The~key~'#1'~is~missing~a~key-type~\msg_line_context:. }
  {
    Each~key~in~a~template~requires~a~key-type,~given~in~the~form:\\
    \ \ <key>~:~<key-type>\\
    LaTeX~could~not~find~a~<key-type>~in~your~input.
  }
\msg_new:nnnn { template } { key-no-value }
  { The~key~'#1'~has~no~value~\msg_line_context:. }
  {
    When~creating~an~instance~of~a~template~
    every~key~listed~must~include~a~value:\\
    \ \ <key>~=~<value>
  }
\msg_new:nnnn { template } { key-no-variable }
  { The~key~'#1'~requires~implementation~details~\msg_line_context:. }
  {
    When~creating~template~code~using~\DeclareTemplateCode,~
    each~key~name~must~have~an~associated~implementation.\\
    This~should~be~given~after~a~'='~sign:~LaTeX~did~not~find~one.
  }
\msg_new:nnnn { template } { key-not-implemented }
  { Key~'#1'~has~no~implementation~\msg_line_context:. }
  {
    The~definition~of~key~implementations~for~template~'#2'~
    of~template~type~'#3'~does~not~include~any~details~for~key~'#1'.\\
    The~key~was~declared~in~the~interface~definition,~
    and~so~an~implementation~is~required.
  }
\msg_new:nnnn { template } { missing-keytype }
  { The~key~'#1'~is~missing~a~key-type~\msg_line_context:. }
  {
    Key~interface~definitions~should~be~of~the~form\\
    \ \ #1~:~<key-type>\\
    but~LaTeX~could~not~find~a~<key-type>.
  }
\msg_new:nnnn { template } { no-template-code }
  {
    The~template~'#2'~of~type~'#1'~is~unknown~
    or~has~no~implementation.
  }
  {
    There~is~no~code~available~for~the~template~name~given.\\
    This~should~be~given~using~\DeclareTemplateCode.
  }
\msg_new:nnnn { template } { type-already-defined }
  { Template~type~'#1'~already~defined. }
  {
    You~have~used~\NewTemplateType~
    with~a~template~type~that~has~already~been~defined.
  }
\msg_new:nnnn { template } { type-mismatch }
  { Template~types~'#1'~and~'#2'~do~not~agree. }
  {
    You~are~trying~to~use~a~template~directly~with~\UseInstance
    (or~a~similar~function),~but~the~template~types~do~not~match.
  }
\msg_new:nnnn { template } { unknown-attribute }
  { The~template~attribute~'#1'~is~unknown. }
  {
    There~is~a~definition~in~the~current~template~reading\\
    \ \ \token_to_str:N \KeyValue {~#1~} \\
    but~there~is~no~key~called~'#1'.
  }
\msg_new:nnnn { template } { unknown-choice }
  { The~choice~'#2'~was~not~declared~for~key~'#1'. }
  {
    The~key~'#1'~takes~a~fixed~list~of~choices~
    and~this~list~does~not~include~'#2'.
  }
\msg_new:nnnn { template } { unknown-default-choice }
  { The~default~choice~'#2'~was~not~declared~for~key~'#1'. }
  {
    The~key~'#1'~takes~a~fixed~list~of~choices~
    and~this~list~does~not~include~'#2'.
  }
\msg_new:nnnn { template } { unknown-expansion }
  { The~expansion~type~'#1'~is~unknown. }
  {
    Key~values~can~only~be~expanded~using~one~of~the~pre-defined~methods:~
    n,~o,~V,~v,~e,~N~or~c.
  }
\msg_new:nnnn { template } { unknown-instance }
  { The~instance~'#2'~of~type~'#1'~is~unknown. }
  {
    You~have~asked~to~use~an~instance~'#2',~
    but~this~has~not~been~created.
  }
\msg_new:nnnn { template } { unknown-key }
  { Unknown~template~key~'#1'. }
  {
    The~key~'#1'~was~not~declared~in~the~interface~
    for~the~current~template.
  }
\msg_new:nnnn { template } { unknown-keytype }
  { The~key-type~'#1'~is~unknown. }
  {
    Valid~key-types~are:\\
    -~boolean;\\
    -~choice;\\
    -~commalist;\\
    -~function;\\
    -~instance;\\
    -~integer;\\
    -~length;\\
    -~muskip;\\
    -~real;\\
    -~skip;\\
    -~tokenlist.
  }
\msg_new:nnnn { template } { unknown-type }
  { The~template~type~'#1'~is~unknown. }
  {
    A~template~type~needs~to~be~defined~with~\NewTemplateType
    prior~to~using~it.
  }
\msg_new:nnnn { template } { unknown-template }
  { The~template~'#2'~of~type~'#1'~is~unknown. }
  {
    No~interface~has~been~declared~for~a~template~
    '#2'~of~template~type~'#1'.
  }
%    \end{macrocode}
%
% Information messages only have text: more text should not be needed.
%    \begin{macrocode}
\msg_new:nnn { template } { declare-instance }
  { Declaring~instance~~'#1'~of~type~#2~\msg_line_context:. }
\msg_new:nnn { template } { declare-template-code }
  { Declaring~code~for~template~'#2'~of~template~type~'#1'~\msg_line_context:. }
\msg_new:nnn { template } { declare-template-interface }
  {
    Declaring~interface~for~template~'#2'~of~template~type~'#1'~
    \msg_line_context:.
  }
\msg_new:nnn { template } { declare-type }
  { Declaring~template~type~'#1'~taking~#2~argument(s)~\msg_line_context:. }
\msg_new:nnn { template } { show-attribute }
  {
    The~template~'#2'~of~type~'#1'~has~
    \tl_if_empty:nTF {#4} { no~#3. } { #3 : #4 }
  }
\msg_new:nnn { template } { show-values }
  {
    The~instance~'#2'~of~type~'#1'~has~
    \tl_if_empty:nTF {#3} { no~values. } { values: #3 }
  }
%    \end{macrocode}
%
%   Also add \pkg{template} to the \pkg{LaTeX} messages.
%    \begin{macrocode}
\prop_gput:Nnn \g_msg_module_type_prop { template } { LaTeX }
%    \end{macrocode}
%
% \subsection{User functions}
%
% \begin{macro}{\NewTemplateType}
% \begin{macro}{\DeclareTemplateInterface}
% \begin{macro}{\DeclareTemplateCode}
% \begin{macro}{\DeclareTemplateCopy}
% \begin{macro}{\EditTemplateDefaults}
% \begin{macro}{\UseTemplate}
% \begin{macro}{\DeclareInstance}
% \begin{macro}{\DeclareInstanceCopy}
% \begin{macro}{\EditInstance}
% \begin{macro}{\UseInstance}
%   All simple translations.
%    \begin{macrocode}
\cs_new_protected:Npn \NewTemplateType #1#2
  { \@@_define_type:nn {#1} {#2} }
\cs_new_protected:Npn \DeclareTemplateInterface #1#2#3#4
  { \@@_declare_template_keys:nnnn {#1} {#2} {#3} {#4} }
\cs_new_protected:Npn \DeclareTemplateCode #1#2#3#4#5
  { \@@_declare_template_code:nnnnn {#1} {#2} {#3} {#4} {#5} }
\cs_new_protected:Npn \DeclareTemplateCopy #1#2#3
  { \@@_template_set_eq:nnn {#1} {#2} {#3} }
\cs_new_protected:Npn \EditTemplateDefaults #1#2#3
  { \@@_edit_defaults:nnn {#1} {#2} {#3} }
\cs_new_protected:Npn \UseTemplate #1#2#3
  { \@@_use_template:nnn {#1} {#2} {#3} }
\cs_new_protected:Npn \DeclareInstance #1#2#3#4
  { \@@_declare_instance:nnnn {#1} {#3} {#2} {#4} }
\cs_new_protected:Npn \DeclareInstanceCopy #1#2#3
  { \@@_instance_set_eq:nnn {#1} {#2} {#3} }
\cs_new_protected:Npn \EditInstance #1#2#3
  { \@@_edit_instance:nnn {#1} {#2} {#3} }
\cs_new_protected:Npn \UseInstance #1#2
  { \@@_use_instance:nn {#1} {#2} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ShowTemplateCode}
% \begin{macro}{\ShowTemplateDefaults}
% \begin{macro}{\ShowTemplateInterface}
% \begin{macro}{\ShowTemplateVariables}
% \begin{macro}{\ShowInstanceValues}
%   The show functions are again just translation.
%    \begin{macrocode}
\cs_new_protected:Npn \ShowTemplateCode #1#2
  { \@@_show_code:nn {#1} {#2} }
\cs_new_protected:Npn \ShowTemplateDefaults #1#2
  { \@@_show_defaults:nn {#1} {#2} }
\cs_new_protected:Npn \ShowTemplateInterface #1#2
  { \@@_show_keytypes:nn {#1} {#2} }
\cs_new_protected:Npn \ShowTemplateVariables #1#2
  { \@@_show_vars:nn {#1} {#2} }
\cs_new_protected:Npn \ShowInstanceValues #1#2
  { \@@_show_values:nn {#1} {#2} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\IfInstanceExistsT, \IfInstanceExistsF, \IfInstanceExistsTF}
% \changes{2024-02-15}{v1.0b}{New macros}
% \changes{2024-04-17}{v1.0c}{Use plural names}
%   More direct translation.
%    \begin{macrocode}
\cs_new:Npn \IfInstanceExistsTF #1#2
  { \@@_if_instance_exist:nnTF {#1} {#2} }
\cs_new:Npn \IfInstanceExistsT #1#2
  { \@@_if_instance_exist:nnT {#1} {#2} }
\cs_new:Npn \IfInstanceExistsF #1#2
  { \@@_if_instance_exist:nnF {#1} {#2} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\KeyValue}
%   Simply dump the argument when executed: this should not happen.
%    \begin{macrocode}
\cs_new_protected:Npn \KeyValue #1 {#1}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\InstanceValue}
% \changes{2025-11-21}{v1.0g}{New command}
%    \begin{macrocode}
\cs_new:Npn \InstanceValue #1#2#3
   { \@@_instance_value:nnn {#1} {#2} {#3} }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AssignTemplateKeys}
%   A short call to use a token register by proxy.
%    \begin{macrocode}
\cs_new_protected:Npn \AssignTemplateKeys { \@@_assignments_pop: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\SetKnownTemplateKeys,\SetTemplateKeys}
%   A friendly wrapper, with some speed up for the common case of the
%    third argument being empty.
% \changes{2025-01-08}{v1.0d}{Test for empty key/val list to speed up processing}
%    \begin{macrocode}
\cs_new_protected:Npn \SetKnownTemplateKeys #1#2#3
  {
    \tl_if_empty:oTF {#3}
      {
        \tl_set_eq:NN  \UnusedTemplateKeys \c_empty_tl
      }
      {
        \keys_set_known:noN { template / #1 / #2 } {#3} \UnusedTemplateKeys
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \SetTemplateKeys #1#2#3
  {
    \tl_if_empty:oF {#3}
      {
        \keys_set:no { template / #1 / #2 } {#3}
      }
  }
%    \end{macrocode}
%    
%    \begin{macrocode}
\tl_new:N \UnusedTemplateKeys
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{lttemplates}%
%<latexrelease>                 {Prototype~document~commands}%
%<latexrelease>
%<latexrelease>\EndModuleRelease
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOff
%    \end{macrocode}
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%    \end{macrocode}
%
% We need to stop DocStrip treating |@@| in a special way at this point.
%    \begin{macrocode}
%<@@=>
%    \end{macrocode}
%
% \Finale
